home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2007 December / PCWKCD1207B.iso / Blogowanie poza sfera / Flock 1.0 beta / flock-1.0RC3.en-US.win32.exe / flock / components / flockMagnoliaService.js < prev    next >
Text File  |  2007-10-18  |  24KB  |  643 lines

  1. // BEGIN FLOCK GPL
  2. // 
  3. // Copyright Flock Inc. 2005-2007
  4. // http://flock.com
  5. // 
  6. // This file may be used under the terms of of the
  7. // GNU General Public License Version 2 or later (the "GPL"),
  8. // http://www.gnu.org/licenses/gpl.html
  9. // 
  10. // Software distributed under the License is distributed on an "AS IS" basis,
  11. // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. // for the specific language governing rights and limitations under the
  13. // License.
  14. // 
  15. // END FLOCK GPL
  16.  
  17. const CC = Components.classes;
  18. const CI = Components.interfaces;
  19. const CR = Components.results;
  20. const CU = Components.utils;
  21.  
  22. CU.import("resource:///modules/FlockXPCOMUtils.jsm");
  23. FlockXPCOMUtils.debug = false;
  24.  
  25. CU.import("resource:///modules/FlockSvcUtils.jsm");
  26. CU.import("resource:///modules/deliciousApi.jsm");
  27. CU.import("resource:///modules/onlineFavoritesBackend.jsm");
  28.  
  29. const MODULE_NAME = "Magnolia";
  30.  
  31. const CLASS_NAME = "Flock Magnolia Service";
  32. const CLASS_SHORT_NAME = "magnolia"
  33. const CLASS_TITLE = "Magnolia"
  34. const CLASS_ID = Components.ID("{7c9aa278-85ed-4cbe-b0bc-f35df0978ade}");
  35. const CONTRACT_ID = "@flock.com/magnolia-service;1";
  36.  
  37. const SERVICE_ENABLED_PREF = "flock.service.magnolia.enabled";
  38.  
  39. const MAGNOLIA_STRING_BUNDLE = "chrome://flock/locale/services/magnolia.properties";
  40. const MAGNOLIA_URL = "http://ma.gnolia.com";
  41. const MAGNOLIA_FAVICON = "http://ma.gnolia.com/favicon.ico";
  42. const MAGNOLIA_API_URL = "https://ma.gnolia.com/api/mirrord/v1/";
  43. const MAGNOLIA_USER_URL_BASE = "http://ma.gnolia.com/people";
  44.  
  45. // One minute, expressed in nsITimer terms.
  46. const TIMER_SECOND = 1000;
  47.  
  48. /**************************************************************************
  49.  * Component: Flock Magnolia Service
  50.  **************************************************************************/
  51.  
  52. // Constructor.
  53. function flockMagnoliaService() {
  54.   this._init();
  55.  
  56.   FlockSvcUtils.flockIWebService.addDefaultMethod(this, "getAccount");
  57.   FlockSvcUtils.flockIWebService.addDefaultMethod(this, "getAccounts");
  58.   FlockSvcUtils.flockIWebService.addDefaultMethod(this, "logout");
  59.  
  60.   FlockSvcUtils.flockIManageableWebService
  61.                .addDefaultMethod(this, "docRepresentsSuccessfulLogin");
  62.   FlockSvcUtils.flockIManageableWebService
  63.                .addDefaultMethod(this, "getAccountIDFromDocument");
  64.   FlockSvcUtils.flockIManageableWebService
  65.                .addDefaultMethod(this, "getCredentialsFromForm");
  66.   FlockSvcUtils.flockIManageableWebService
  67.                .addDefaultMethod(this, "ownsDocument");
  68.   FlockSvcUtils.flockIManageableWebService
  69.                .addDefaultMethod(this, "ownsLoginForm");
  70. }
  71.  
  72.  
  73. /**************************************************************************
  74.  * Flock Magnolia Service: XPCOM Component Creation
  75.  **************************************************************************/
  76.  
  77. flockMagnoliaService.prototype = new FlockXPCOMUtils.genericComponent(
  78.   CLASS_NAME,
  79.   CLASS_ID,
  80.   CONTRACT_ID,
  81.   flockMagnoliaService,
  82.   CI.nsIClassInfo.SINGLETON,
  83.   [
  84.     CI.nsIObserver,
  85.     CI.nsITimerCallback,
  86.     CI.flockIWebService,
  87.     CI.flockIManageableWebService,
  88.     CI.flockIBookmarkWebService,
  89.     CI.flockIPollingService
  90.   ]
  91. );
  92.  
  93. // FlockXPCOMUtils.genericModule() categories
  94. flockMagnoliaService.prototype._xpcom_categories = [
  95.   { category: "wsm-startup" },
  96.   { category: "flockWebService", entry: CLASS_SHORT_NAME }
  97. ];
  98.  
  99.  
  100. /**************************************************************************
  101.  * Flock Magnolia Service: Private Data and Functions
  102.  **************************************************************************/
  103.  
  104. // Member variables.
  105.  
  106. flockMagnoliaService.prototype._init =
  107. function MagnoliaSvc__init() {
  108.   FlockSvcUtils.getLogger(this).info(".init()");
  109.  
  110.   // Determine whether this service has been disabled, and unregister if so.
  111.   prefService = CC["@mozilla.org/preferences-service;1"]
  112.                 .getService(CI.nsIPrefBranch);
  113.   if (prefService.getPrefType(SERVICE_ENABLED_PREF) &&
  114.      !prefService.getBoolPref(SERVICE_ENABLED_PREF))
  115.   {
  116.     this._logger.info("Pref " + SERVICE_ENABLED_PREF
  117.                               + " set to FALSE... not initializing.");
  118.     this.deleteCategories();
  119.     return;
  120.   }
  121.  
  122.   profiler = CC["@flock.com/profiler;1"].getService(CI.flockIProfiler);
  123.   var evtID = profiler.profileEventStart("magnolia-init");
  124.  
  125.   var obs = CC["@mozilla.org/observer-service;1"]
  126.             .getService(CI.nsIObserverService);
  127.   obs.addObserver(this, "xpcom-shutdown", false);
  128.  
  129.   this._api = new DeliciousAPI(MAGNOLIA_API_URL, this._logger);
  130.   this._accountClassCtor = flockMagnoliaAccount;
  131.   FlockSvcUtils.getACUtils(this);
  132.   FlockSvcUtils.getCoop(this);
  133.   if (this._coop.Service.exists(this.urn)) {
  134.     this._c_svc = this._coop.get(this.urn);
  135.   } else {
  136.     this._c_svc = new this._coop.Service(this.urn, {
  137.       name: CLASS_SHORT_NAME,
  138.       desc: CLASS_TITLE
  139.     });
  140.   }
  141.   this._c_svc.serviceId = CONTRACT_ID;
  142.   this._c_svc.domains = FlockSvcUtils.getWD(this)
  143.                         .getString("magnolia", "domains", "gnolia.com");
  144.  
  145.   profiler.profileEventEnd(evtID, "");
  146. }
  147.  
  148. // Helper to retrieve tags on server.
  149. flockMagnoliaService.prototype._getAllTags =
  150. function MagnoliaSvc__getAllTags(aUrn, aAccountId,
  151.                                  aPassword, aPollingListener) {
  152.   this._logger.debug("getAllTags(...)");
  153.   var svc = this;
  154.  
  155.   var flockListener = {
  156.     onStart: function MagnoliaSvc__getAllTags_onStart(aSubject, aTopic) {
  157.       // Not used.
  158.     },
  159.     onSuccess: function MagnoliaSvc__getAllTags_onSuccess(aSubject, aTopic) {
  160.       svc._logger.info("tags/get SUCCEEDED: " + aTopic);
  161.  
  162.       var tags = [];
  163.       for (var i = 0; i < aSubject.length; i++) {
  164.         tags.push(aSubject[i].tag);
  165.       }
  166.       onlineFavoritesBackend.updateTags(svc, aAccountId, tags);
  167.  
  168.       // Tell the poller we're done
  169.       if (aPollingListener) {
  170.         aPollingListener.onResult();
  171.       }
  172.     },
  173.     onError: function MagnoliaSvc__getAllTags_onError(aSubject, aTopic, aError) {
  174.       svc._logger.error("tags/get FAILED");
  175.       // BUG: 5705 -  report error via notification bar?
  176.       // onlineFavoritesBackend.showNotification(message);
  177.       if (aPollingListener) {
  178.         aPollingListener.onError(aError);
  179.       }
  180.     }
  181.   }
  182.  
  183.   this._api.tagsGet(flockListener, null);
  184. }
  185.  
  186.  
  187. /**************************************************************************
  188.  * Flock Magnolia Service: flockIWebService Implementation
  189.  **************************************************************************/
  190.  
  191. // readonly attribute AString urn;
  192. flockMagnoliaService.prototype.urn = "urn:" + CLASS_SHORT_NAME + ":service";
  193.  
  194. // readonly attribute AString title;
  195. flockMagnoliaService.prototype.title = CLASS_TITLE;
  196.  
  197. // readonly attribute AString icon;
  198. flockMagnoliaService.prototype.icon = MAGNOLIA_FAVICON;
  199.  
  200. // readonly attribute AString url;
  201. flockMagnoliaService.prototype.url = MAGNOLIA_URL;
  202.  
  203. // readonly attribute AString contractId;
  204. // ALMOST duplicated by nsIClassInfo::contractID
  205. // with different case: contractId != contractID
  206. flockMagnoliaService.prototype.contractId = CONTRACT_ID;
  207.  
  208. // readonly attribute AString shortName;
  209. flockMagnoliaService.prototype.shortName = CLASS_SHORT_NAME;
  210.  
  211. // readonly attribute boolean needPassword;
  212. flockMagnoliaService.prototype.needPassword = true;
  213.  
  214. // flockIWebServiceAccount addAccountById(in AString aAccountID,
  215. //                                        in boolean aIsTransient,
  216. //                                        in flockIListener aListener);
  217. flockMagnoliaService.prototype.addAccountById =
  218. function MagnoliaSvc_addAccountById(aAccountID, aIsTransient, aListener) {
  219.   this._logger.debug("addAccountById('" + aAccountID + "', "
  220.                      + aIsTransient + ", aListener)");
  221.   var acct = onlineFavoritesBackend.createAccount(this,
  222.                                                   aAccountID, aIsTransient);
  223.   if (aListener) {
  224.     aListener.onSuccess(acct, "addAccount");
  225.   }
  226.   return acct;
  227. }
  228.  
  229. // void removeAccount(in AString aUrn);
  230. flockMagnoliaService.prototype.removeAccount =
  231. function MagnoliaSvc_removeAccount(aUrn) {
  232.   this._logger.debug("removeAccount('" + aUrn + "')");
  233.   onlineFavoritesBackend.removeAccount(this, aUrn);
  234. }
  235.  
  236. // DEFAULT: flockIWebServiceAccount getAccount(in AString aUrn);
  237. // DEFAULT: nsISimpleEnumerator getAccounts();
  238. // DEFAULT: void logout();
  239.  
  240. // readonly attribute long status;
  241. flockMagnoliaService.prototype.status = CI.flockIWebService.STATUS_UNKNOWN;
  242.  
  243.  
  244. /**************************************************************************
  245.  * Flock Magnolia Service: flockIManageableWebService Implementation
  246.  **************************************************************************/
  247.  
  248. // DEFAULT: boolean docRepresentsSuccessfulLogin(in nsIDOMHTMLDocument aDocument);
  249. // DEFAULT: AString getAccountIDFromDocument(in nsIDOMHTMLDocument aDocument);
  250. // DEFAULT: nsIPassword getCredentialsFromForm(in nsIDOMHTMLFormElement aForm);
  251. // DEFAULT: boolean ownsDocument(in nsIDOMHTMLDocument aDocument);
  252. // DEFAULT: boolean ownsLoginForm(in nsIDOMHTMLFormElement aForm);
  253.  
  254. // void updateAccountStatusFromDocument(in nsIDOMHTMLDocument aDocument);
  255. flockMagnoliaService.prototype.updateAccountStatusFromDocument =
  256. function MagnoliaSvc_updateAccountStatusFromDocument(aDocument) {
  257.   this._logger.debug("updateAccountStatusFromDocument()");
  258.  
  259.   if (this._WebDetective.detect("magnolia", "loggedout", aDocument, null)) {
  260.     this._acUtils.markAllAccountsAsLoggedOut(CONTRACT_ID);
  261.   } else {
  262.     if (this._WebDetective.detect("magnolia", "loggedin", aDocument, null)) {
  263.       var results = FlockSvcUtils.newResults();
  264.       if (this._WebDetective.detect("magnolia",
  265.                                     "accountinfo", aDocument, results))
  266.       {
  267.         var accountID = results.getPropertyAsAString("accountid");
  268.         var accountURN = this._acUtils.getAccountURNById(this.urn, accountID);
  269.         this._acUtils.ensureOnlyAuthenticatedAccount(accountURN);
  270.       }
  271.     }
  272.   }
  273. }
  274.  
  275.  
  276. /**************************************************************************
  277.  * Flock Magnolia Service: flockIBookmarkWebService Implementation
  278.  **************************************************************************/
  279.  
  280. // void publish (in flockIListener aListener, in AString aAccountId,
  281. //               in flockIBookmark aBookmark, in boolean aPrivate);
  282. flockMagnoliaService.prototype.publish =
  283. function MagnoliaSvc_publish(aListener, aAccountId, aBookmark, aPrivate) {
  284.   this._logger.info("Publish(" + aBookmark.URL + "," + aBookmark.name
  285.                     + ") to " + aAccountId + "@Magnolia");
  286.   var accountUrn = this.urn + ":" + aAccountId;
  287.   var password = this._acUtils.getPassword(accountUrn);
  288.   var svc = this;
  289.   var args = {
  290.     url: aBookmark.URL,
  291.     description: aBookmark.name,
  292.     extended: aBookmark.description,
  293.     tags: (aBookmark.tags ? aBookmark.tags.split(/[\s,]/).sort().join(",") : "")
  294.   };
  295.   if (aPrivate) {
  296.     args.shared = "no";
  297.   }
  298.  
  299.   var deliciousApiListener = {
  300.     onError: function MagnoliaSvc_publish_onError(aError) {
  301.       svc._logger.error("posts/add FAILED");
  302.       // BUG: 5705 -  report error via notification bar?
  303.       // onlineFavoritesBackend.showNotification(message);
  304.       if (aListener) {
  305.         aListener.onError(svc, "publish", aError);
  306.       }
  307.     },
  308.     onSuccess: function MagnoliaSvc_publish_onSuccess(aXML) {
  309.       svc._logger.info("posts/add SUCCEEDED");
  310.  
  311.       // Validate the nsIDOMDocument response.
  312.       if (!svc._api.isExpectedResponse(aXML, "result")) {
  313.         svc._logger.error("posts/add succeeded - but with invalid xml response");
  314.         // BUG: 5705 -  report error via notification bar?
  315.         // onlineFavoritesBackend.showNotification(message);
  316.         if (aListener) {
  317.           var error = CC["@flock.com/error;1"].createInstance(CI.flockIError);
  318.           // FIXME: fill in this flockIError.
  319.           error.errorCode = CI.flockIError.FAVS_UNKNOWN_ERROR;
  320.           aListener.onError(svc, "publish", error);
  321.         }
  322.         return;
  323.       } else {
  324.         // Process the validated response.
  325.         var result = aXML.documentElement.getAttribute("code");
  326.         svc._logger.debug(" Result for posts/add: " + result);
  327.         if (result == "done") {
  328.           var localBookmarks = svc._coop.get(svc.urn + ":"
  329.                                              + aAccountId + ":bookmarks");
  330.           var tags = aBookmark.tags.split(" ");
  331.           for (i in tags) {
  332.             localBookmarks.tag.addOnce(tags[i]);
  333.           }
  334.           onlineFavoritesBackend.updateBookmark(svc, accountUrn,
  335.                                                 aBookmark, aPrivate);
  336.           if (aListener) {
  337.             aListener.onSuccess(svc, "publish");
  338.           }
  339.         } else if (aListener) {
  340.           var error = CC["@flock.com/error;1"].createInstance(CI.flockIError);
  341.           // FIXME: fill in this flockIError.
  342.           error.errorCode = CI.flockIError.FAVS_UNKNOWN_ERROR;
  343.           aListener.onError(svc, "publish", error);
  344.         }
  345.       }
  346.     }
  347.   }
  348.  
  349.   this._api.call("posts/add", args, deliciousApiListener, password);
  350. }
  351.  
  352. // void publishList (in flockIListener aListener, in AString aAccountId,
  353. //                   in nsISimpleEnumerator aBookmarkList, in boolean aPrivate);
  354. flockMagnoliaService.prototype.publishList =
  355. function MagnoliaSvc_publishList(aListener, aAccountId, aBookmarkList, aPrivate) {
  356.   var delay = 1000; // 1 second between each query
  357.   var svc = this;
  358.   var i = 0;
  359.   var bookmarks = [];
  360.  
  361.   var syncCallback = {
  362.     notify: function publishListCallback_notify(timer) {
  363.       var bm = bookmarks.shift();
  364.       svc.publish(aListener, aAccountId, bm, aPrivate);
  365.     }
  366.   }
  367.  
  368.   while (aBookmarkList.hasMoreElements()) {
  369.     var bookmark = aBookmarkList.getNext().QueryInterface(CI.flockIBookmark);
  370.     // Duplicate it because it's going to be removed too early
  371.     bookmarks[i] = {};
  372.     bookmarks[i].URL = bookmark.URL;
  373.     bookmarks[i].name = bookmark.name;
  374.     bookmarks[i].description = bookmark.description;
  375.     bookmarks[i].tags = bookmark.tags;
  376.     bookmarks[i].time = bookmark.time;
  377.  
  378.     this._logger.debug("Set a timer to " + i * delay
  379.                        + " for " + bookmarks[i].URL);
  380.     var publishTimer = CC["@mozilla.org/timer;1"]
  381.                        .createInstance(CI.nsITimer);
  382.     publishTimer.initWithCallback(syncCallback, i * TIMER_SECOND,
  383.                                   CI.nsITimer.TYPE_ONE_SHOT);
  384.     i++;
  385.   }
  386. }
  387.  
  388. // void remove (in flockIListener aListener, in AString aAccountId,
  389. //              in AString aBookmark);
  390. flockMagnoliaService.prototype.remove =
  391. function MagnoliaSvc_remove(aListener, aAccountId, aBookmark) {
  392.   this._logger.info("Remove " + aBookmark + " from "
  393.                     + aAccountId + "@Magnolia");
  394.   var password = this._acUtils.getPassword(this.urn + ":" + aAccountId);
  395.   var svc = this;
  396.   var args = { url: aBookmark };
  397.  
  398.   var deliciousApiListener = {
  399.     onError: function MagnoliaSvc_remove_onError(aError) {
  400.       svc._logger.error("posts/delete FAILED");
  401.       // BUG: 5705 -  report error via notification bar?
  402.       // onlineFavoritesBackend.showNotification(message);
  403.       if (aListener) {
  404.         aListener.onError(svc, "remove", aError);
  405.       }
  406.     },
  407.     onSuccess: function MagnoliaSvc_remove_onSuccess(aXML) {
  408.       svc._logger.info("posts/delete SUCCEEDED");
  409.  
  410.       // Validate the nsIDOMDocument response.
  411.       if (!svc._api.isExpectedResponse(aXML, "result")) {
  412.         svc._logger.error("posts/delete succeeded - but with invalid xml response");
  413.         // BUG: 5705 -  report error via notification bar?
  414.         // onlineFavoritesBackend.showNotification(message);
  415.         if (aListener) {
  416.           var error = CC["@flock.com/error;1"].createInstance(CI.flockIError);
  417.           // FIXME: fill in this flockIError.
  418.           error.errorCode = CI.flockIError.FAVS_UNKNOWN_ERROR;
  419.           aListener.onError(svc, "remove", error);
  420.         }
  421.       } else {
  422.         // Process the validated response.
  423.         var result = aXML.documentElement.getAttribute("code");
  424.         svc._logger.debug("Result for posts/delete: " + result);
  425.         if (result == "done") {
  426.           onlineFavoritesBackend.destroyBookmark(svc, aAccountId, aBookmark);
  427.           CC["@flock.com/poller-service;1"].getService(CI.flockIPollerService)
  428.           .forceRefresh(this.urn + ":" + aAccountId + ":bookmarks");
  429.           if (aListener) {
  430.             aListener.onSuccess(svc, "remove");
  431.           }
  432.         } else if (aListener) {
  433.           var error = CC["@flock.com/error;1"].createInstance(CI.flockIError);
  434.           // FIXME: fill in this flockIError.
  435.           error.errorCode = CI.flockIError.FAVS_UNKNOWN_ERROR;
  436.           aListener.onError(svc, "remove", error);
  437.         }
  438.       }
  439.     }
  440.   }
  441.  
  442.   this._api.call("posts/delete", args, deliciousApiListener, password);
  443. }
  444.  
  445. // boolean exists (in AString aAccountId, in AString aURL);
  446. flockMagnoliaService.prototype.exists =
  447. function MagnoliaSvc_exists(aAccountId, aURL) {
  448.   return this._coop.Bookmark.exists(this.urn + ":" + aAccountId + ":" + aURL);
  449. }
  450.  
  451. // AString getUserURL (in AString aAccountId);
  452. flockMagnoliaService.prototype.getUserUrl =
  453. function MagnoliaSvc_getUserUrl(aAccountId) {
  454.   return MAGNOLIA_USER_URL_BASE + "/" + aAccountId;
  455. }
  456.  
  457.  
  458. /**************************************************************************
  459.  * Flock Magnolia Service: flockIPollingService Implementation
  460.  **************************************************************************/
  461.  
  462. // void refresh(in AString aUrn, in flockIPollingListener aListener);
  463. flockMagnoliaService.prototype.refresh =
  464. function MagnoliaSvc_refresh(aURN, aPollingListener) {
  465.   var svc = this;
  466.   this._logger.info("refresh(" + aURN + ")");
  467.  
  468.   if (!this._coop.OnlineBookmarksStream.exists(aURN)) {
  469.     throw "flockMagnoliaService: " + aURN + " can't be found";
  470.   }
  471.  
  472.   var bookmarks = this._coop.get(aURN);
  473.   var accountId = bookmarks.userid;
  474.   var accountUrn = this.urn + ":" + accountId;
  475.   // nsIPassword for auth for this sync
  476.   var password = this._acUtils.getPassword(accountUrn);
  477.  
  478.   var flockListener = {
  479.     onStart: function MagnoliaSvc_refresh_onStart(aSubject, aTopic) {
  480.       // Not used.
  481.     },
  482.     onSuccess: function MagnoliaSvc_refresh_onSuccess(aSubject, aTopic) {
  483.       svc._logger.info("posts/all SUCCEEDED: " + aTopic);
  484.  
  485.       if (aTopic != "nonew") {
  486.         onlineFavoritesBackend.updateLocal(svc, aSubject, aTopic, accountUrn);
  487.         // Now refresh the tag list (wait one second)
  488.         var syncCallback = {
  489.           notify: function refreshCallback_notify(aTimer) {
  490.             svc._getAllTags(aURN, accountId, password, aPollingListener);
  491.           }
  492.         }
  493.         svc._logger.debug("Setting timer to execute _getAllTags()");
  494.         svc._timer = CC["@mozilla.org/timer;1"].createInstance(CI.nsITimer);
  495.         svc._timer.initWithCallback(syncCallback, TIMER_SECOND,
  496.                                     CI.nsITimer.TYPE_ONE_SHOT);
  497.         // For "updated" case, syncCallback calls onResult().
  498.       } else if (aPollingListener) {
  499.         aPollingListener.onResult();
  500.       }
  501.     },
  502.     onError: function MagnoliaSvc_refresh_onError(aSubject, aTopic, aError) {
  503.       svc._logger.error("posts/all FAILED: ["
  504.                         + aError.errorCode + "] "
  505.                         + aError.errorString + " (["
  506.                         + aError.serviceErrorCode + "] "
  507.                         + aError.serviceErrorString + ")");
  508.       var sbs = CC["@mozilla.org/intl/stringbundle;1"]
  509.                 .getService(CI.nsIStringBundleService);
  510.       var bundle = sbs.createBundle(MAGNOLIA_STRING_BUNDLE);
  511.       var message;
  512.       switch (aError.errorCode) {
  513.         case CI.flockIError.FAVS_UNAVAILABLE:
  514.           message = bundle.GetStringFromName("flock.magnolia.error.unavailable");
  515.           break;
  516.         case CI.flockIError.FAVS_INVALID_AUTH:
  517.           message = bundle.GetStringFromName("flock.magnolia.error.invalid");
  518.           break;
  519.         default:
  520.           var stringName = "flock.magnolia.error";
  521.           message = bundle.formatStringFromName(stringName,
  522.                                                 [aError.serviceErrorString,
  523.                                                  aError.errorServiceCode],
  524.                                                 2);
  525.           break;
  526.       }
  527.       onlineFavoritesBackend.showNotification(message);
  528.       if (aPollingListener) {
  529.         aPollingListener.onError(aError);
  530.       }
  531.     }
  532.   }
  533.  
  534.   // even for the first refresh, we need to get the last update time from 
  535.   // the server. Bruno
  536.   this._api.postsUpdate(flockListener, password, bookmarks.last_update_time);
  537. }
  538.  
  539. /**************************************************************************
  540.  * Flock Magnolia Service: nsIObserver Implementation
  541.  **************************************************************************/
  542.  
  543. flockMagnoliaService.prototype.observe =
  544. function MagnoliaSvc_observe(aSubject, aTopic, aState) {
  545.   switch (aTopic) {
  546.     case "xpcom-shutdown":
  547.       var obs = CC["@mozilla.org/observer-service;1"]
  548.                 .getService(CI.nsIObserverService);
  549.       obs.removeObserver(this, "xpcom-shutdown");
  550.       break;
  551.   }
  552. }
  553.  
  554. /**************************************************************************
  555.  * Component: Flock Magnolia Account
  556.  **************************************************************************/
  557.  
  558. function flockMagnoliaAccount() {
  559.   FlockSvcUtils.getLogger(this).info(".init()");
  560.   FlockSvcUtils.getACUtils(this);
  561.   FlockSvcUtils.getCoop(this);
  562.  
  563.   FlockSvcUtils.flockIWebServiceAccount.addDefaultMethod(this, "deactivate");
  564.   FlockSvcUtils.flockIWebServiceAccount.addDefaultMethod(this, "login");
  565.   FlockSvcUtils.flockIWebServiceAccount.addDefaultMethod(this, "logout");
  566.   FlockSvcUtils.flockIWebServiceAccount.addDefaultMethod(this, "remove");
  567. }
  568.  
  569. /**************************************************************************
  570.  * Flock Magnolia Account: XPCOM Component Creation
  571.  **************************************************************************/
  572.  
  573. // Use genericComponent() for the goodness it provides (QI, nsIClassInfo, etc),
  574. // but do NOT add flockMagnoliaAccount to the list of constructors passed
  575. // to FlockXPCOMUtils.genericModule().
  576. flockMagnoliaAccount.prototype = new FlockXPCOMUtils.genericComponent(
  577.   CLASS_NAME + " Account",
  578.   "",
  579.   "",
  580.   flockMagnoliaAccount,
  581.   0,
  582.   [
  583.     CI.flockIWebServiceAccount,
  584.     CI.flockIBookmarkWebServiceAccount,
  585.   ]
  586.   );
  587.  
  588. /**************************************************************************
  589.  * Flock Magnolia Account: flockIWebServiceAccount Implementation
  590.  **************************************************************************/
  591.  
  592. // readonly attribute AString urn;
  593. flockMagnoliaAccount.prototype.urn = "";
  594.  
  595. // void activate(in flockIListener aListener);
  596. flockMagnoliaAccount.prototype.activate =
  597. function MagnoliaAcct_activate(aListener) {
  598.   this._logger.debug("activate()");
  599.   this._coop.get(this.urn).isAuthenticated = true;
  600.   this._coop.get(this.urn + ":bookmarks").isPollable = true;
  601.   if (aListener) {
  602.     aListener.onSuccess(this, "activate");
  603.   }
  604. }
  605.  
  606. // DEFAULT: void deactivate(in flockIListener aListener);
  607. // DEFAULT: void login(in flockIListener aListener);
  608. // DEFAULT: void logout(in flockIListener aListener);
  609.  
  610. // void keep();
  611. flockMagnoliaAccount.prototype.keep =
  612. function MagnoliaAcct_keep() {
  613.   this._logger.debug("keep()");
  614.   this._coop.get(this.urn).isTransient = false;
  615.   this._coop.get(this.urn+":bookmarks").isTransient = false;
  616.   this._acUtils.makeTempPasswordPermanent(this.urn);
  617. }
  618.  
  619. // DEFAULT: void remove();
  620.  
  621.  
  622. /**************************************************************************
  623.  * Flock Magnolia Account: flockIBookmarkWebServiceAccount Implementation
  624.  **************************************************************************/
  625.  
  626. /* No methods or properties on this interface! */
  627.  
  628.  
  629. /**************************************************************************
  630.  * XPCOM Support - Module Construction
  631.  **************************************************************************/
  632.  
  633. // Create array of components.
  634. var gComponentsArray = [flockMagnoliaService];
  635.  
  636. // Generate a module for XPCOM to find.
  637. var NSGetModule = FlockXPCOMUtils.generateNSGetModule(MODULE_NAME,
  638.                                                       gComponentsArray);
  639.  
  640. /**************************************************************************
  641.  * END XPCOM Support
  642.  **************************************************************************/
  643.